var url = require('url');
var path = require('path');
var formidable = require('formidable');
var uuid = require('uuid/v4');
var cookies = require('./cookies');
var fileUtil = require('../sys/fileUtil');

class request {
    constructor(req, res, sessionManager, exec) {
        var njsid = uuid();
        var ck = new cookies(req.headers.cookie);
        if (ck.get('njsid')) {
            njsid = ck.get('njsid');
        } else {
            res.setHeader('Set-Cookie', 'njsid=' + njsid + '; path=/; httpOnly=true');
        }
        req.cookies = ck;
        req.njsid = njsid;
        sessionManager.read(njsid, session => {
            this.parse(req, res, session, exec);
        });
    }

    parse(req, res, session, exec) {
        var pathParseInfos = url.parse(req.originalUrl);
        for (var prop in pathParseInfos) {
            req[prop] = pathParseInfos[prop];
        }
        if (!req.port) {
            req.port = req.protocol == 'https:' ? '443' : '80';
        }
        var ext = fileUtil.getFileExt(pathParseInfos.pathname);
        req.ext = ext;
        req.session = session;
        req.setTimeout(sysConfig.requestTimeout, function () {
            req.emit('error', req.url + ' 请求超时');
        });
        req.on('error', function (err) {
            try {
                res.send500(err);
            } catch (e) {}
        });
        req.getClientIp = function (headerName) {
            return (req.headers[headerName || 'x-forwarded-for'] || req.connection.remoteAddress || req.socket.remoteAddress || '').replace('::ffff:', '');
        };
        req.query = url.parse(req.url, true).query;
        req.form = Object.create(null);
        req.formBody = '';
        req.files = Object.create(null);

        if (req.method == 'POST') {
            var formBody = '';
            fileUtil.mkdirs(sysConfig.uploadTemp, function () {
                var form = new formidable.IncomingForm();
                form.uploadDir = sysConfig.uploadTemp;
                form.encoding = 'utf-8';
                form.maxFieldsSize = sysConfig.uploadMaxFieldsSize;
                form.maxFields = sysConfig.uploadMaxFields;
                form.multiples = true;
                form.hash = 'md5';
                var maxFileSize = sysConfig.uploadMaxFileSize;
                var fields = Object.create(null);
                var files = Object.create(null);
                form.on('fileBegin', function (name, file) {
                    var _ext = path.extname(file.name);
                    _ext = _ext ? _ext.slice(1) : '';
                    if (!sysConfig.uploadType.includes(_ext)) {
                        req.emit('error', req.url + ' 上传文件格式被禁止');
                    }
                }).on('field', function (name, value) {
                    if (formBody != '')
                        formBody += '&';
                    formBody += name + '=' + value;
                    if (fields[name]) {
                        fields[name] = typeof fields[name] == 'string' ? [fields[name]] : fields[name];
                        fields[name].push(value);
                    } else {
                        fields[name] = value;
                    }
                }).on('file', function (name, file) {
                    if (files[name]) {
                        files[name] = typeof files[name] == 'string' ? [files[name]] : files[name];
                        files[name].push(file);
                    } else {
                        files[name] = file;
                    }
                }).on('progress', function (bytesReceived, bytesExpected) {
                    if (bytesExpected > maxFileSize) {
                        req.emit('error', req.url + ' 上传文件大小超过限制');
                    }
                }).on('error', function (err) {
                    req.emit('error', err);
                }).on('end', function () {
                    req.form = fields;
                    req.formBody = formBody;
                    req.files = files;
                    exec();
                }).parse(req);
            });
        } else {
            exec();
        }
    }
}

module.exports = request;